﻿//Author:Michal Sporna
//License: https://operationsneakpeek.codeplex.com/license

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Util.Classes
{
    /// <summary>
    /// Represents in world obstacle
    /// </summary>
    public class Obstacle
    {
        
        #region properties
        public string ID;//unique ID of the obstacle 
        //public Vector2 Location { get; set; } //it is in ObstacleToDraw now as it's unique for each map cell
        public int Width;
        public int Height;
        public Helpers.PublicEnums.ObstacleType Type; //type of the obstacle
        public double DynamicChangeTime;//after what period of time, dynamic item's state changes
        public int HarmMultiplier; //a random number is multiplied by this and such harm is made to the avatar (if obstacle harmful)
        public string TextureName;
        public int OffsetRight;
        public int OffsetLeft;
        public int OffsetDown;
        public int OffsetUp;
        public bool IsWater;
        public bool Walkable;
        public Helpers.PublicEnums.ShieldType ShieldType;
        public List<Helpers.ObstacleInteractingItemHelper> ItemsInteracting; //list of items that can interact with that obstacle
        public List<Event> Events; //holds an event that triggers a method after an item is used
       
        

        //so avatar could touch it.
        ////Touchables determine which part of obstacle can be touched by avatar
        //public int TouchableStart { get; set; }
        //public int TouchableEnd { get; set; }
        //sounds
        //TO BE IMPLEMENTED HERE AND XML

        #endregion

        #region public fields
        //helpers
        public string ObstacleTypeString;
        public string ShieldTypeString;

        #endregion

        #region private

        //NOT BEING USED ANYMORE (REPLACED BY WORLD.IsObstacleTouched)
        #region collision detection

        /// <summary>
        /// Is collision from the left?
        /// </summary>
        /// <param name="ObstaclePos"></param>
        /// <returns></returns>
        private bool _IsCollisionFromLeft(Vector2 ObstaclePos, Rectangle avatarRect, Rectangle obstacleRect)
        {
            try
            {
                                                                                                                        
                if ((avatarRect.Right >= obstacleRect.Left + OffsetLeft && avatarRect.Right<=obstacleRect.Right) && (avatarRect.Bottom >= obstacleRect.Top+OffsetUp && avatarRect.Top <= obstacleRect.Bottom-OffsetDown))
                {
                    //reset future position
                    Cache.Avatar.FuturePosition = Cache.Avatar.CurrentPosition;
                    //return true
                    return true;
                }

                
                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }
        }
        
        /// <summary>
        /// Is collision from the right?
        /// </summary>
        /// <param name="ObstaclePos"></param>
        /// <returns></returns>
        private bool _IsCollisionFromRight(Vector2 ObstaclePos,Rectangle avatarRect,Rectangle obstacleRect)
        {
            try
            {

                if ((avatarRect.Left <= obstacleRect.Right - OffsetRight && avatarRect.Left >= obstacleRect.Left) && (avatarRect.Bottom >= obstacleRect.Top + OffsetUp && avatarRect.Top <= obstacleRect.Bottom - OffsetDown))
                {
                    //reset future position
                    Cache.Avatar.FuturePosition = Cache.Avatar.CurrentPosition;
                    //return true
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }
        }

        /// <summary>
        /// Is collision from Up?
        /// </summary>
        /// <param name="ObstaclePos"></param>
        /// <returns></returns>
        private bool _IsCollisionFromUp(Vector2 ObstaclePos, Rectangle avatarRect, Rectangle obstacleRect)
        {
            try
            {
                if ((avatarRect.Bottom >= obstacleRect.Top + OffsetUp && avatarRect.Bottom <= obstacleRect.Bottom) && (avatarRect.Right >= obstacleRect.Left + OffsetLeft && avatarRect.Left <= obstacleRect.Right - OffsetRight))
                {
                    //reset future position
                    Cache.Avatar.FuturePosition = Cache.Avatar.CurrentPosition;
                    //return true
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }
        }


        /// <summary>
        /// Is collision from down?
        /// </summary>
        /// <param name="ObstaclePos"></param>
        /// <returns></returns>
        private bool _IsCollisionFromDown(Vector2 ObstaclePos, Rectangle avatarRect, Rectangle obstacleRect)
        {
            try
            {
                if ((avatarRect.Top<= obstacleRect.Bottom - OffsetDown && avatarRect.Top >= obstacleRect.Top) && (avatarRect.Right >= obstacleRect.Left + OffsetLeft && avatarRect.Left <= obstacleRect.Right - OffsetRight))
                {
                    //reset future position
                    Cache.Avatar.FuturePosition = Cache.Avatar.CurrentPosition;
                    //return true
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }
        }


        #endregion 

        

        #endregion

        #region methods

        /// <summary>
        /// default constructor
        /// </summary>
        public Obstacle()
        {
            try
            {
                ID= "NewObstacle";
                Type = Helpers.PublicEnums.ObstacleType.StaticNoHarm;
                HarmMultiplier = 0;
                ObstacleTypeString = null;
                ShieldType = Helpers.PublicEnums.ShieldType.None;
        

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }

        }


        /// <summary>
        /// custom constructor 1
        /// </summary>
        public Obstacle(string name, Vector2 location, Helpers.PublicEnums.ObstacleType type, int harmMultiplier)
        {
            try
            {
                this.ID = name;
                this.Type = type;
                this.HarmMultiplier = harmMultiplier;
                ShieldType = Helpers.PublicEnums.ShieldType.None;
                

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }

        }


        /// <summary>
        /// Convert all values from temporary string
        /// to types
        /// </summary>
        public void DoConvertions()
        {
            try
            {

                #region parameters of the events

                for (int i = 0; i < this.Events.Count; i++)
                {
                    //Event
                    #region event type

                    switch (this.Events[i].EventTypeString)
                    {
                        case "NONE":
                            {
                                this.Events[i].EventType = Util.Helpers.PublicEnums.EventType.None;
                                this.Events[i].EventTypeString = null;
                                break;
                            }
                        case "onInteraction":
                            {
                                this.Events[i].EventType = Util.Helpers.PublicEnums.EventType.OnInteraction;
                                this.Events[i].EventTypeString = null;
                                break;
                            }
                        case "onLandmineStepped":
                            {
                                this.Events[i].EventType = Util.Helpers.PublicEnums.EventType.onLandmineStepped;
                                this.Events[i].EventTypeString = null;
                                break;
                            }
                    }



                    #endregion


                    //fpreach param
                    for (int i1 = 0; i1 < this.Events[i].Parameters.Count; i1++)
                    {
                        switch (this.Events[i].Parameters[i1].ParameterString)
                        {
                            case "this":
                                {
                                    this.Events[i].Parameters[i1].Parameter = this;
                                    //this.Events[i].Parameters[i1].ParameterString = null;

                                    break;
                                }
                            case "NULL":
                                {
                                    this.Events[i].Parameters[i1].Parameter = null;
                                    //this.Events[i].Parameters[i1].ParameterString = null;

                                    break;
                                }

                        }
                    }
                }


                #endregion

                //shield type
                switch (ShieldTypeString)
                {
                    case "None":
                        {
                            ShieldType = Helpers.PublicEnums.ShieldType.None;
                            break;
                        }
                    case "Up":
                        {
                            ShieldType = Helpers.PublicEnums.ShieldType.Up;
                            break;
                        }
                    case "Down":
                        {
                            ShieldType = Helpers.PublicEnums.ShieldType.Down;
                            break;
                        }
                    case "UpDown":
                        {
                            ShieldType = Helpers.PublicEnums.ShieldType.UpDown;
                            break;
                        }
                }

                ShieldTypeString = null;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }

        }


        //NOT BEING USED ANYMORE (REPLACED BY WORLD.IsObstacleTouched) :
        #region is obstacle touched?

        /// <summary>
        /// if obstacle is touched, return true
        /// if obstacle is touched and it can harm avatar, harm avatar
        /// </summary>
        /// <returns></returns>
        public bool IsObstacleTouched(Vector2 ObstaclePos)
        {

            try
            {
               

                //see if this.location overlaps with cache.avatar.location

                //if yes, if obstacle is harmful, then harm avatar
                //by calling avatar.MakeHarm(int hpToTakeAway) (it plays harm animation and deducts life points)

                //if avatar is not on the map yet,return false
                if (Cache.Avatar == null)
                {
                    return false;
                }

                //draw help rectangles
                Rectangle avatarRect = new Rectangle((int)Cache.Avatar.FuturePosition.X, (int)Cache.Avatar.FuturePosition.Y, Cache.Avatar.Width,Cache.Avatar.Height);
                //Rectangle obstacleRect = new Rectangle((int)ObstaclePos.X+OffsetLeft, (int)ObstaclePos.Y+OffsetUp, this.Width-OffsetRight-OffsetLeft, this.Height-OffsetDown-OffsetUp);
                Rectangle obstacleRect = new Rectangle((int)ObstaclePos.X, (int)ObstaclePos.Y, this.Width, this.Height);
                
                //offsets
                obstacleRect.X += OffsetLeft;
                obstacleRect.Width += OffsetRight;
                obstacleRect.Y += OffsetUp;
                obstacleRect.Height += OffsetDown;

           

                //see if touching
                if (obstacleRect.Intersects(avatarRect))
                {
                    return true;
                }


           

                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }


        }

        

        /// <summary>
        /// if obstacle is touched, return true
        /// the only difference with isObstacleTouched(V2 obstaclePos) 
        /// is that here the avatar's position is implicitly specified 
        /// </summary>
        /// <returns></returns>
        public bool IsObstacleTouched(int[] ObstaclePos,int[] avatarPos)
        {

            try
            {

                //draw help rectangles
                Rectangle avatarRect = new Rectangle(avatarPos[0], avatarPos[1], avatarPos[2], avatarPos[3]);
                //Rectangle obstacleRect = new Rectangle((int)ObstaclePos.X+OffsetLeft, (int)ObstaclePos.Y+OffsetUp, this.Width-OffsetRight-OffsetLeft, this.Height-OffsetDown-OffsetUp);
                Rectangle obstacleRect = new Rectangle(ObstaclePos[0], ObstaclePos[1], ObstaclePos[2], ObstaclePos[3]);

                //offsets
                obstacleRect.X += OffsetLeft;
                obstacleRect.Width += OffsetRight;
                obstacleRect.Y += OffsetUp;
                obstacleRect.Height += OffsetDown;



                //see if touching
                if (obstacleRect.Intersects(avatarRect))
                {
                    return true;
                }




                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }


        }

        /// <summary>
        /// if obstacle is touched, return true
        /// </summary>
        /// <returns></returns>
        public bool IsObstacleTouched(Vector2 ObstaclePos, Vector2 point, int objectWidth, int objectHeight)
        {
            try
            {

                //draw help rectangles
                //AVATAR RECT IS USED HERE, although it is not avatar we check if touching obstacle
                Rectangle avatarRect = new Rectangle((int)point.X, (int)point.Y, objectWidth, objectHeight);
                Rectangle obstacleRect = new Rectangle((int)ObstaclePos.X, (int)ObstaclePos.Y, this.Width, this.Height);

                if ((_IsCollisionFromDown(ObstaclePos, avatarRect, obstacleRect)) || (_IsCollisionFromUp(ObstaclePos, avatarRect, obstacleRect)) || (_IsCollisionFromRight(ObstaclePos, avatarRect, obstacleRect)) || (_IsCollisionFromLeft(ObstaclePos, avatarRect, obstacleRect)))
                {
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return false;
            }


        }



        #endregion


        #endregion




    }
}
